﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace BeanboxSoftware.BeanMap
{
  static class SerializationInfoExntensions
  {
    public static T GetValue<T>(this SerializationInfo info, string name)
    {
      return ((T)(info.GetValue(name, typeof(T))));
    }
  }

  namespace Internal
  {
    [Serializable]
    public abstract partial class DictionaryCommonBase<TKey, TValue>
    {
      private static readonly string DATA_STORAGE = "_data";

      protected DictionaryCommonBase(SerializationInfo info, StreamingContext sc)
        : this()
      {
        _storage = NewStorage();
        _storage.DataStorage = info.GetValue<Dictionary<TKey, TValue>>(DATA_STORAGE);
      }

      protected virtual void GetObjectDataImpl(SerializationInfo info, StreamingContext context)
      {
        WriteStorage();        
        info.AddValue(DATA_STORAGE, _storage.DataStorage);
      }

      [OnDeserialized]
      private void OnDeserialized(StreamingContext context)
      {
        ReadStorage();
      }
    }

    [Serializable]
    public abstract partial class MapBase<TGen, TValue, TPrimaryKey, TPrimaryValue> : DictionaryCommonBase<TPrimaryKey, TPrimaryValue>, ISerializable
    {
      private static readonly string KEYNOTFOUNDBEHAVIOR_STORAGE = "KeyNotFoundBehavior";
      private static readonly string DEFAULTVALUESTORAGE_STORAGE = "DefaultValueStorage";

      private bool _faultedGeneration;

      protected MapBase(SerializationInfo info, StreamingContext sc)
        : base(info, sc)
      {
        (_storage as MapBaseSerialData).KeyNotFoundBehaviorStorage = info.GetValue<KeyNotFoundBehavior>(KEYNOTFOUNDBEHAVIOR_STORAGE);
        (_storage as MapBaseSerialData).DefaultValueStorage = info.GetValue<TValue>(DEFAULTVALUESTORAGE_STORAGE);
      }

      protected override void GetObjectDataImpl(SerializationInfo info, StreamingContext context)
      {
        base.GetObjectDataImpl(info, context);
        info.AddValue(KEYNOTFOUNDBEHAVIOR_STORAGE, (_storage as MapBaseSerialData).KeyNotFoundBehaviorStorage);
        info.AddValue(DEFAULTVALUESTORAGE_STORAGE, (_storage as MapBaseSerialData).DefaultValueStorage);
      }

      void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
      {
        GetObjectDataImpl(info, context);
      }
    }
  }

  // outside internal
  [Serializable]
  public partial class Map<K, V> : Internal.MapBase<Func<K, V>, V, K, V>, ISerializable
  {
    protected Map(SerializationInfo info, StreamingContext sc)
      : base(info, sc)
    {
    }
  }

  [Serializable]
  public partial class Map<K1, K2, V> : Internal.MapBase<Func<K1, K2, V>, V, K1, IDictionary<K2, V>>, ISerializable
  {
    protected Map(SerializationInfo info, StreamingContext sc)
      : base(info, sc)
    {
    }
  }

  [Serializable]
  public partial class Map<K1, K2, K3, V> : Internal.MapBase<Func<K1, K2, K3, V>, V, K1, IDictionary<K2, IDictionary<K3, V>>>, ISerializable
  {
    protected Map(SerializationInfo info, StreamingContext sc)
      : base(info, sc)
    {
    }
  }
}
